package com.github.niefy.modules.openapi.client.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpUtil;
import com.aliyun.oss.ServiceException;
import com.github.niefy.common.utils.EhCacheUtils;
import com.github.niefy.common.utils.HttpClientUtil;
import com.github.niefy.modules.openapi.client.dto.in.IMPIn_001;
import com.github.niefy.modules.openapi.client.dto.in.IMPIn_002;
import com.github.niefy.modules.openapi.client.dto.out.IMPOut;
import com.github.niefy.modules.openapi.client.dto.out.IMPOut_001;
import com.github.niefy.modules.openapi.client.dto.out.IMPOut_002;
import com.github.niefy.modules.openapi.client.enums.AppSecretClientEnum;
import com.github.niefy.modules.openapi.client.service.IMPService;
import com.github.niefy.modules.third.entity.ThirdSysInfo;
import com.github.niefy.modules.third.enums.IMActionEnum;
import com.github.niefy.modules.third.enums.SecApiURLEnum;
import com.github.niefy.modules.third.service.ThirdSysInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * @author : [86188]
 * @description : 智慧化管理平台开放平台功能提供
 * @createTime : [2023/5/5 10:02]
 * @updateUser : [86188]
 * @updateTime : [2023/5/5 10:02]
 */
@Service
@Slf4j
public class IMPServiceImpl implements IMPService {

    @Autowired
    private ThirdSysInfoService thirdSysInfoService;


    /**
     * 获取微信公众号内跳转访问路径
     * @param out
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    public IMPIn_002 getMpUrl(IMPOut_002 out) throws IOException, InterruptedException {
        var in = httpPostJsonSync(IMActionEnum.query_wx_mp_access.name(), IMPIn_002.class, out);
        return in;
    }

    /**
     * 获取 access_token
     * 1、检查本地缓存是否存在对应access_token
     * 2、存在，检查access_token是否临过期(剩余存活时间小于300_000毫秒），临过期重新获取
     * 3、不存在，获取
     */
    private String getAccessToken(){
        //检查本地缓存是否存在对应access_token,存在且未临过期直接返回
        var appAccessClientTokenElement = EhCacheUtils.getNativeElement(AppSecretClientEnum.IM.getAppId(), "appAccessClientTokenCache");
        boolean oldTokenExist = BeanUtil.isNotEmpty(appAccessClientTokenElement);
        if (oldTokenExist){
            var expiresIn = appAccessClientTokenElement.getCreationTime() + appAccessClientTokenElement.getTimeToLive() * 1000L - System.currentTimeMillis();
            if (expiresIn > 300_000){
                return (String) appAccessClientTokenElement.getObjectValue();
            }
        }
        //其他情况获取并缓存
        String appid = AppSecretClientEnum.IM.getAppId();
        Long millisecond = System.currentTimeMillis();
        var thirdSysInfo = thirdSysInfoService.lambdaQuery()
                .eq(ThirdSysInfo::getClientAppid, AppSecretClientEnum.IM.getAppId())
                .one();
        String signature  = DigestUtil.md5Hex(IMActionEnum.access_token.name() + appid + millisecond + thirdSysInfo.getClientSecret());
        var out = IMPOut_001.builder()
                .action(IMActionEnum.access_token.toString())
                .appid(appid)
                .millisecond(millisecond)
                .signature(signature)
                .build();
        var in = HttpClientUtil.http2GetJsonSync(thirdSysInfo.getDomain() + SecApiURLEnum.SPM_CALL, IMPIn_001.class, out);
        var access_token = in.getAccess_token();
        if (StrUtil.isBlank(access_token)){
            log.error("获取智慧化管理平台access_token异常："+ in);
            throw new ServiceException("");
        }
        EhCacheUtils.put(AppSecretClientEnum.IM.getAppId(), access_token, "appAccessClientTokenCache");
        return access_token;
    }


    /**
     * 向智慧化管理平台发送POST请求
     * @param <T>
     * 1、调用getAccessToken，拼装url及url参数
     * 2、发送请求将结果返回
     */
    private <T> T httpPostJsonSync(String action, Class<T> responseType, Object outParam) throws IOException, InterruptedException {
        var accessToken = getAccessToken();
        var urlParam = IMPOut.builder()
                .access_token(accessToken)
                .action(action)
                .build();
        String domain = thirdSysInfoService.lambdaQuery()
                .eq(ThirdSysInfo::getClientAppid, AppSecretClientEnum.IM.getAppId())
                .one()
                .getDomain();
        var urlWithForm = HttpUtil.urlWithForm(domain + SecApiURLEnum.SPM_CALL, BeanUtil.beanToMap(urlParam, true, true), StandardCharsets.UTF_8, false);
        var responseBean = HttpClientUtil.http2PostJsonSync(urlWithForm, outParam, responseType);
        return responseBean;
    }
}
